package org.microsleep.sqlite;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;

import org.microsleep.PersistentClass;
import org.microsleep.Property;
import org.microsleep.Session;
import org.microsleep.Type;

import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteStatement;
import android.util.Log;

public class SQLiteSession extends Session {

	private final SQLiteDatabase database;

	public SQLiteSession(SQLiteDatabase database) {
		super(new SQLiteUtil());
		this.database = database;
	}

	@Override
	protected void executeStatement(Object stmt,
			Collection<Property> properties, Map<Property, Object> values) {
		SQLiteStatement statement = (SQLiteStatement) stmt;
		statement.clearBindings();
		int i = 1;
		for (Property property : properties) {
			Object value = values.get(property);
			bind(statement, i, property, value);
			i++;
		}
		Log.d(getClass().getName(), "Executing " + statement);
		statement.execute();
	}

	@Override
	protected Map<Property, Object> executeQuery(Object stmt,
			List<Property> properties, Property identifier, Object id) {
		String statement = (String) stmt;
		Log.d(getClass().getName(), "Executing " + statement);
		Cursor cursor = database.rawQuery(statement,
				new String[] { String.valueOf(id) });
		if (cursor.getCount() > 1) {
			throw new IllegalStateException("More than one object with id "
					+ id + " found!");
		}
		if (cursor.moveToFirst()) {
			Map<Property, Object> values = new HashMap<Property, Object>();
			int i = 0;
			for (Property property : properties) {
				Type type = property.getType();
				if (type instanceof PersistentClass) {
					PersistentClass pClass = (PersistentClass) type;
					type = pClass.getIdentifier().getType();
				}
				@SuppressWarnings("unchecked")
				SQLiteType<Object> sqliteType = (SQLiteType<Object>) type;
				Object javaValue;
				javaValue = sqliteType.getJavaValue(cursor, i);
				values.put(property, javaValue);
				i++;
			}
			return values;
		}
		throw new NoSuchElementException("Object with id " + id + " not found.");
	}

	private void bind(SQLiteStatement statement, int i, Property property,
			Object value) {
		if (value == null) {
			statement.bindNull(i);
		} else {
			Type type = property.getType();
			if (type instanceof PersistentClass) {
				PersistentClass pClass = (PersistentClass) type;
				Property id = pClass.getIdentifier();
				type = id.getType();
				value = id.getValue(value);
			}
			@SuppressWarnings("unchecked")
			SQLiteType<Object> sqliteType = (SQLiteType<Object>) type;
			sqliteType.bindInStatement(statement, i, property, value);
		}
	}

	@Override
	protected Object compileStore(String statement) {
		return database.compileStatement(statement);
	}

	@Override
	protected Object compileLoad(String statement) {
		return statement;
	}

	@Override
	protected Object compileCreateTable(String statement) {
		return database.compileStatement(statement);
	}

}
